using System;
using System.Collections;
using System.Collections.Generic;

namespace Universe.Threading
{

    internal class RangeEnumerable_Int32 : IEnumerable<Int32>
    {
        private readonly Int32 _from;
        private readonly Int32 _to;
        private readonly Int32 _step;

        internal RangeEnumerable_Int32(Int32 from, Int32 to, Int32 step)
        {
            if (step == 0)
                throw new ArgumentException("Zero Step of RangeFor is invalid", "step");

            _from = from;
            _to = to;
            _step = step;

        }

        internal static RangeEnumerable_Int32 AnyDirection(Int32 start, Int32 end)
        {
            Int32 step = (Int32)(start > end ? -1 : 1);
            return new RangeEnumerable_Int32(start, end, step);
        }

        public IEnumerator<Int32> GetEnumerator()
        {
            return new RangeEnumerator_Int32(this);
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return new RangeEnumerator_Int32(this);
        }

        struct RangeEnumerator_Int32 : IEnumerator<Int32>
        {
            private bool _isFirst;
            private Int32 _current;

            private readonly RangeEnumerable_Int32 _range;

            public RangeEnumerator_Int32(RangeEnumerable_Int32 range)
            {
                _range = range;
                _current = _range._from;
                _isFirst = true;

            }

            public Int32 Current
            {
                get
                {
                    return _current;
                }
            }

            public void Dispose()
            {
            }

            public bool MoveNext()
            {
                if (_isFirst)
                {
                    _isFirst = false;
                    bool has = _range._step > 0 ? _current <= _range._to : _current >= _range._to;
                    return has;
                }

                if (OverflowTest.HasOverflow(_current, _range._step))
                    return false;

                Int32 tryNext = (Int32)(_current + _range._step);
                bool isDone = _range._step > 0 ? tryNext > _range._to : tryNext < _range._to;

                if (isDone)
                    return false;
                else
                {
                    _current = tryNext;
                    return true;
                }
            }

            void IEnumerator.Reset()
            {
                _current = _range._from;
            }

            object IEnumerator.Current
            {
                get { return _current; }
            }
        }
    }

    internal class RangeEnumerable_Int64 : IEnumerable<Int64>
    {
        private readonly Int64 _from;
        private readonly Int64 _to;
        private readonly Int64 _step;

        internal RangeEnumerable_Int64(Int64 from, Int64 to, Int64 step)
        {
            if (step == 0)
                throw new ArgumentException("Zero Step of RangeFor is invalid", "step");

            _from = from;
            _to = to;
            _step = step;

        }

        internal static RangeEnumerable_Int64 AnyDirection(Int64 start, Int64 end)
        {
            Int64 step = (Int64)(start > end ? -1 : 1);
            return new RangeEnumerable_Int64(start, end, step);
        }

        public IEnumerator<Int64> GetEnumerator()
        {
            return new RangeEnumerator_Int64(this);
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return new RangeEnumerator_Int64(this);
        }

        struct RangeEnumerator_Int64 : IEnumerator<Int64>
        {
            private bool _isFirst;
            private Int64 _current;

            private readonly RangeEnumerable_Int64 _range;

            public RangeEnumerator_Int64(RangeEnumerable_Int64 range)
            {
                _range = range;
                _current = _range._from;
                _isFirst = true;

            }

            public Int64 Current
            {
                get
                {
                    return _current;
                }
            }

            public void Dispose()
            {
            }

            public bool MoveNext()
            {
                if (_isFirst)
                {
                    _isFirst = false;
                    bool has = _range._step > 0 ? _current <= _range._to : _current >= _range._to;
                    return has;
                }

                if (OverflowTest.HasOverflow(_current, _range._step))
                    return false;

                Int64 tryNext = (Int64)(_current + _range._step);
                bool isDone = _range._step > 0 ? tryNext > _range._to : tryNext < _range._to;

                if (isDone)
                    return false;
                else
                {
                    _current = tryNext;
                    return true;
                }
            }

            void IEnumerator.Reset()
            {
                _current = _range._from;
            }

            object IEnumerator.Current
            {
                get { return _current; }
            }
        }
    }

    internal class RangeEnumerable_Int16 : IEnumerable<Int16>
    {
        private readonly Int16 _from;
        private readonly Int16 _to;
        private readonly Int16 _step;

        internal RangeEnumerable_Int16(Int16 from, Int16 to, Int16 step)
        {
            if (step == 0)
                throw new ArgumentException("Zero Step of RangeFor is invalid", "step");

            _from = from;
            _to = to;
            _step = step;

        }

        internal static RangeEnumerable_Int16 AnyDirection(Int16 start, Int16 end)
        {
            Int16 step = (Int16)(start > end ? -1 : 1);
            return new RangeEnumerable_Int16(start, end, step);
        }

        public IEnumerator<Int16> GetEnumerator()
        {
            return new RangeEnumerator_Int16(this);
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return new RangeEnumerator_Int16(this);
        }

        struct RangeEnumerator_Int16 : IEnumerator<Int16>
        {
            private bool _isFirst;
            private Int16 _current;

            private readonly RangeEnumerable_Int16 _range;

            public RangeEnumerator_Int16(RangeEnumerable_Int16 range)
            {
                _range = range;
                _current = _range._from;
                _isFirst = true;

            }

            public Int16 Current
            {
                get
                {
                    return _current;
                }
            }

            public void Dispose()
            {
            }

            public bool MoveNext()
            {
                if (_isFirst)
                {
                    _isFirst = false;
                    bool has = _range._step > 0 ? _current <= _range._to : _current >= _range._to;
                    return has;
                }

                if (OverflowTest.HasOverflow(_current, _range._step))
                    return false;

                Int16 tryNext = (Int16)(_current + _range._step);
                bool isDone = _range._step > 0 ? tryNext > _range._to : tryNext < _range._to;

                if (isDone)
                    return false;
                else
                {
                    _current = tryNext;
                    return true;
                }
            }

            void IEnumerator.Reset()
            {
                _current = _range._from;
            }

            object IEnumerator.Current
            {
                get { return _current; }
            }
        }
    }

    internal class RangeEnumerable_Decimal : IEnumerable<Decimal>
    {
        private readonly Decimal _from;
        private readonly Decimal _to;
        private readonly Decimal _step;

        internal RangeEnumerable_Decimal(Decimal from, Decimal to, Decimal step)
        {
            if (step == 0)
                throw new ArgumentException("Zero Step of RangeFor is invalid", "step");

            _from = from;
            _to = to;
            _step = step;

        }

        internal static RangeEnumerable_Decimal AnyDirection(Decimal start, Decimal end)
        {
            Decimal step = (Decimal)(start > end ? -1 : 1);
            return new RangeEnumerable_Decimal(start, end, step);
        }

        public IEnumerator<Decimal> GetEnumerator()
        {
            return new RangeEnumerator_Decimal(this);
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return new RangeEnumerator_Decimal(this);
        }

        struct RangeEnumerator_Decimal : IEnumerator<Decimal>
        {
            private bool _isFirst;
            private Decimal _current;

            private readonly RangeEnumerable_Decimal _range;

            public RangeEnumerator_Decimal(RangeEnumerable_Decimal range)
            {
                _range = range;
                _current = _range._from;
                _isFirst = true;

            }

            public Decimal Current
            {
                get
                {
                    return _current;
                }
            }

            public void Dispose()
            {
            }

            public bool MoveNext()
            {
                if (_isFirst)
                {
                    _isFirst = false;
                    bool has = _range._step > 0 ? _current <= _range._to : _current >= _range._to;
                    return has;
                }

                if (OverflowTest.HasOverflow(_current, _range._step))
                    return false;

                Decimal tryNext = (Decimal)(_current + _range._step);
                bool isDone = _range._step > 0 ? tryNext > _range._to : tryNext < _range._to;

                if (isDone)
                    return false;
                else
                {
                    _current = tryNext;
                    return true;
                }
            }

            void IEnumerator.Reset()
            {
                _current = _range._from;
            }

            object IEnumerator.Current
            {
                get { return _current; }
            }
        }
    }

}